/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shaman.storage.impl.stream.size;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 *
 * @author dmitriy
 */
public class SizeLimitInputStream extends FilterInputStream {

    private boolean closed;
    private long offset;
    private final long endOffset;
    private long markOffset, markEndOffset;
    protected boolean closeBaseStream=true;

    public SizeLimitInputStream(InputStream in, long endOffset) {
        super(in);
        closed=false;
        this.endOffset=endOffset;
        markOffset=-1;
    }

    @Override
    public int available() throws IOException {
        if (!closed) {
            int res = in.available();
            long maxres = endOffset - offset;
            return (int) Math.min(res, maxres);
        } else {
            throw new IOException("Stream closed");
        }
    }

    @Override
    public void close() throws IOException {
        if (closeBaseStream) in.close();
        closed=true;
    }


    @Override
    public synchronized void mark(int readlimit) {
        if (!closed) {
            in.mark(readlimit);
            markOffset = offset;
            markEndOffset = offset + readlimit;
        }
    }

    @Override
    public int read() throws IOException {
        if (!closed) {
            int res;
            if (offset < endOffset) {
                res = in.read();
                offset++;
            } else {
                res = -1;
            }
            return res;
        } else {
            throw new IOException("Stream closed");
        }
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if (!closed) {
            int res;
            if (offset < endOffset) {
                int realLen = (int) Math.min(endOffset - offset, len);
                res = in.read(b, off, realLen);
                if (res >= 0) {
                    offset += res;
                }
            } else {
                res = -1;
            }
            return res;
        } else {
            throw new IOException("Stream closed");
        }
    }

    @Override
    public synchronized void reset() throws IOException {
        if (!closed) {
            if (markOffset < 0 || markEndOffset < offset) {
                throw new IOException("No mark set up");
            }
            in.reset();
            offset = markOffset;
            markOffset = -1;
        } else {
            throw new IOException("Stream closed");
        }
    }

    public long getOffset() {
        return offset;
    }

    public boolean isClosed() {
        return closed;
    }

}
